package Modele;
import java.awt.Component;
import java.util.List;
import java.util.Random;
import java.util.Observer;
import java.util.Observable;
import java.util.ArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import Vue.Fenetre;



public class MonteCarloSimulation extends Observable {
	

	private String CallPutFlag;
	private double S; 
	private double X;
	private double r;
	private double T; 
	private double b; 
	private double v; 
	private int nSteps; 
	private int nSimulations;

	private double result;
	private double res;
	  
	
	public MonteCarloSimulation(){
		this.S=40.0;
		this.X=50.0;
		this.r=0.06;
		this.T=0.5;
		this.b=0.1;
		this.v=0.45;
		this.nSteps=168;
		this.nSimulations=100000;
	
		//this.addObserver(o);
	}
	
	
	
	public String getCallPutFlag() {
		return CallPutFlag;
	}
	public void setCallPutFlag(String callPutFlag) {
		CallPutFlag = callPutFlag;
	}
	public double getS() {
		return S;
	}
	public void setS(double s) {
		S = s;
	}
	public double getX() {
		return X;
	}
	public void setX(double x) {
		X = x;
	}
	public double getT() {
		return T;
	}
	public void setT(double t) {
		T = t;
	}
	public double getR() {
		return r;
	}
	public void setR(double r) {
		this.r = r;
	}
	public double getB() {
		return b;
	}
	public void setB(double b) {
		this.b = b;
	}
	public double getV() {
		return v;
	}
	public void setV(double v) {
		this.v = v;
	}
	

	public int getnSteps() {
		return nSteps;
	}
	public void setnSteps(int nSteps) {
		this.nSteps = nSteps;
	}
	public int getnSimulations() {
		return nSimulations;
	}
	public void setnSimulations(int nSimulations) {
		this.nSimulations = nSimulations;
	}
	
	public double calcule(String CallPutFlag)
		{
					
					double dt;
					double St;
					double Sum=0;
					double Drift; 
					double vSqrdt;
					
					int z=0;
					Random rand=new Random();
					
					
		
					
					MyCallable appel = new MyCallable();
					appel.getAll(CallPutFlag, S, X, r, T, b, v, nSteps, nSimulations);
					
					appel.mycall();
					
					
					

					
			       
					dt = T / nSteps;
					Drift = (b - v*v / 2) * dt;
					vSqrdt = v * java.lang.Math.sqrt(dt);
					if ("call".equals(CallPutFlag)){
						z=1; 
					}
					else if ("putt".equals(CallPutFlag)){
						z=-1; 
					}
					for (int k=1; k<=nSimulations; k++){
						St = S; 
						//System.out.println("k= "+k+" :St=  "+ St);
						for (int l=1; l<=nSteps; l++){
							St = St * (java.lang.Math.exp(Drift + vSqrdt *rand.nextGaussian())); 
							//System.out.println("l= "+l+" :St=  "+ St);
							//execute.execute(new MonRunnable());
						}
						Sum = Sum + java.lang.Math.max(z*(St-X), 0); 
						//System.out.println("k= "+k+" :Sum= "+ Sum);
						res=(java.lang.Math.exp((-r*T))*(Sum/nSimulations)); 
						setRes(res);
						//System.out.println("res"+res);
					
					}
					
					
					double result = (java.lang.Math.exp((-r*T))*(Sum/nSimulations)); 
					System.out.println("res final "+result);
					
					return result; 
		}
	
		
		public void setRes(double res){
			//System.out.println("res: "+res);
			//this.addObserver(new Fenetre());
			this.setChanged();
			this.notifyObservers(this.getRes());
			//System.out.println("setresult: "+this.getRes());

		}
		public double getRes() {
			//On avertit les observateurs que l'heure a été mise à jour
			return res;
		}
		
		public static void executeRunnables(final ExecutorService service, List<Runnable> runnables){

			for(Runnable r : runnables){
				service.execute(r);
			}
			//On ferme l'executor une fois les taches finies
			//En effet shutdown va attendre la fin d'exécution des tâches
			service.shutdown();
		}
	

}
